Skip to content

fix(interpreter): budget pending array expansions - #2670

Merged
chaliy merged 2 commits into
mainfrom
codex/array-preexpansion-memory
Oct 11, 2026
Merged

chaliy merged 2 commits into
mainfrom
codex/array-preexpansion-memory

Conversation

@chaliy

@chaliy chaliy commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

What changed

Indexed/assoc array literals with duplicate subscripts now charge every pending element value against the live-intermediate byte budget, not just the values that survive. The expansion pass also holds the budget as leases instead of materializing duplicate copies, so transient memory stays bounded by the configured limit.

Why

Finding [SECURITY-ARRAY-PREEXPANSION-MEMORY]: a literal such as a=([0]= \$big [0]= \$big ...) (2000 dups x 1MB = ~2GB pending) bypassed the byte cap because the committer charged only the final surviving value. The in-memory peak scaled with the number of duplicate entries, an unauthenticated memory-exhaustion vector for any service executing scripts under a memory limit.

Before / After

Before (vulnerable code, budget check on final values only): 2GB transient allocation succeeds under a 10MB budget.

After (fixed): the same shape fails fast with a memory-limit error and the shell stays usable:

  • indexed_array_pending_values_share_live_byte_limit: dup-subscript literal exhausts the live-byte limit -> error, shell usable afterward
  • assoc_array_pending_values_share_live_byte_limit: assoc dup-key literal with distinct live entries -> error, shell usable afterward
  • assoc_array_duplicate_keys_share_live_byte_limit: dup assoc keys charged per occurrence
  • 7 new unit tests in limits.rs / interpreter/tests.rs cover small-literal fast path, dup-subscript commit charging, lease reuse, exhaustion errors, live-usage accounting

E2E smoke (hardened profile, 8KB value x 1200 dup subscripts = ~9.6MB pending vs 8MB limit): shell prints the memory-limit error and exits 1 instead of ballooning.

Risk

  • Low. Changes only the array-literal code path; non-duplicate literals take the same fast path as before (verified by unit test). Full just test slice run in CI.
  • What can break: scripts relying on over-budget duplicate-heavy literals succeeding would now get a memory-limit error -- that is the intended fix.

Checklist

  • Tests added or updated
  • Backward compatibility considered (internal code, no compat needed; over-budget literals erroring is intended)

Produced by yolop

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bashkit 14cfe29 Commit Preview URL

Branch Preview URL
Oct 10 2026, 11:34 PM

@chaliy
chaliy force-pushed the codex/array-preexpansion-memory branch from 85cbd79 to 3f8a4d1 Compare October 10, 2026 23:14
expand_word_inner awaited expand_word_buffer inline, embedding the loop state machine in every $(...) nesting level. Depth-32 aborted under coverage instrumentation (same class as #1089). Box::pin moves the buffer state to the heap, restoring the upstream stack threshold.
@chaliy
chaliy merged commit cf15b45 into main Oct 11, 2026
49 checks passed
@chaliy
chaliy deleted the codex/array-preexpansion-memory branch October 11, 2026 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant